<?php
namespace utils;
use think\Cache;
use think\Config;

class JssdkWechat {
	private $appId;
	private $appSecret;
    protected $redis  = null;
    protected $prefix = "";
    protected $expire = "";

	public function __construct($appId, $appSecret) {
		$this -> appId = $appId;
		$this -> appSecret = $appSecret;

        $this->redis  = Cache::store('redis')->handler();
        $redisConfig  = Config::get('cache.default');
        $this->prefix = $redisConfig['prefix'];
        $this->expire = $redisConfig['expire'];
	}

	public function getSignPackage($p_url='',$oauth_type='kmgzh') {
		$jsapiTicket = $this -> getJsApiTicket($oauth_type);

		// 注意 URL 一定要动态获取，不能 hardcode.
		$protocol = ((isset($_SERVER['HTTP_USE_HTTPS']) && $_SERVER['HTTP_USE_HTTPS'] == 1)) || (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
		if ( $p_url != '' ) {
            $url = $p_url;
        } else {
            $url = "$protocol$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
        }
		$timestamp = time();
		$nonceStr = $this -> createNonceStr();

		// 这里参数的顺序要按照 key 值 ASCII 码升序排序
		$string = "jsapi_ticket=$jsapiTicket&noncestr=$nonceStr&timestamp=$timestamp&url=$url";

		$signature = sha1($string);

		$signPackage = array("appId" => $this -> appId, "nonceStr" => $nonceStr, "timestamp" => $timestamp, "url" => $url, "signature" => $signature, "rawString" => $string);
		return $signPackage;
	}

	private function createNonceStr($length = 16) {
		$chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
		$str = "";
		for ($i = 0; $i < $length; $i++) {
			$str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
		}
		return $str;
	}
/*
	public function getJsApiTicket() {
		// jsapi_ticket 应该全局存储与更新，以下代码以写入到文件中做示例
		$data = json_decode(file_get_contents("oauth_jsapi_ticket.json"));
		if ($data -> expire_time < time()) {
			$accessToken = $this -> getAccessToken();
			// 如果是企业号用以下 URL 获取 ticket
			// $url = "https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket?access_token=$accessToken";
			$url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=$accessToken";
			$res = json_decode($this -> httpGet($url));
			$ticket = $res -> ticket;
			if ($ticket) {
				$data -> expire_time = time() + 7000;
				$data -> jsapi_ticket = $ticket;
				$fp = fopen("oauth_jsapi_ticket.json", "w");
				fwrite($fp, json_encode($data));
				fclose($fp);
			}
		} else {
			$ticket = $data -> jsapi_ticket;
		}

		return $ticket;
	}

	public function getAccessToken() {
		// access_token 应该全局存储与更新，以下代码以写入到文件中做示例
		$data = json_decode(file_get_contents("oauth_access_token.json"));
		if ($data -> expire_time < time()) {
			// 如果是企业号用以下URL获取access_token
			// $url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=$this->appId&corpsecret=$this->appSecret";
			$url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=$this->appId&secret=$this->appSecret";
			$res = json_decode($this -> httpGet($url));
			$access_token = $res -> access_token;
			if ($access_token) {
				$data -> expire_time = time() + 7000;
				$data -> access_token = $access_token;
				$fp = fopen("oauth_access_token.json", "w");
				fwrite($fp, json_encode($data));
				fclose($fp);
			}
		} else {
			$access_token = $data -> access_token;
		}
		return $access_token;
	}
*/
	public function getAccessToken($oauth_type='kmgzh') {
		if(ENVIRONMENT_MODE >= 3){
	        //直接走www.ktvme.net获取
	        //$oauth_type = 'kmgzh';
	        $arrInput = array(
	            'oauth_type' => $oauth_type
	        );

	        $sign = $this->getAuthSignStr($arrInput);

	        $access_token_url = C('WX_OAUTH_URL')."/oauth/getOauthAccessToken?oauth_type=".$oauth_type."&sign=".$sign;
	        $access_token_array = json_decode($this->https_request($access_token_url),TRUE);

	        require_once( './Apps/Common/Lib/func/Curl3Des.class.php' );
	        $des = new \Curl3Des();
	        $key = md5($sign);
	        $access_token = $des->decrypt($access_token_array['oauth_token'], $key);

	        return $access_token;
		}else{
	        // 缓存初始化
	        //$redis  = \Common\Lib\Redis\RedisSingleton::getInstance(array('host' => C('OAUTH_REDIS.HOST'), 'port' => C('OAUTH_REDIS.PORT'), 'index' => 1));
			$redis_key = "weixin:oauth_access_token".$this->appId;
			$expire = 7000;
			
			$cache = "";
			if ($this->redis) {
				$cache = $this->redis ->get($redis_key);
			}
			if (!empty($cache)) {//有缓存则直接返回
				return $cache;
			}
			
			$url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=$this->appId&secret=$this->appSecret";
			$res = json_decode($this -> httpGet($url));
			$access_token = isset($res->access_token)?$res->access_token:'';
			if ($access_token) {
                $this->redis?$this->redis->set($redis_key, $access_token, $expire):'';
			}
			
			return $access_token;
		}
	}
	
	public function getJsApiTicket($oauth_type='kmgzh') {
		if(ENVIRONMENT_MODE >= 3){
			//直接通过www.ktvme.net授权获取
	        //$oauth_type = 'kmgzh';
	        $arrInput = array(
	            'oauth_type' => $oauth_type
	        );

	        $sign = $this->getAuthSignStr($arrInput);

	        $jsapi_ticket_url = C('WX_OAUTH_URL')."/oauth/getOauthJsApiTicket?oauth_type=".$oauth_type."&sign=".$sign;
	        $jsapi_ticket_array = json_decode($this->https_request($jsapi_ticket_url),TRUE);

	        require_once( './Apps/Common/Lib/func/Curl3Des.class.php' );
	        $des = new \Curl3Des();
	        $key = md5($sign);
	        $ticket = $des->decrypt($jsapi_ticket_array['oauth_jsapi_ticket'], $key);

	        return $ticket;
		}else{
			// 缓存初始化
	        //$redis  = \Common\Lib\Redis\RedisSingleton::getInstance(array('host' => C('OAUTH_REDIS.HOST'), 'port' => C('OAUTH_REDIS.PORT'), 'index' => 1));
			$redis_key = "weixin:oauth_jsapi_ticket".$this->appId;
			$expire = 7000;

			$cache = "";
			if ($this->redis) {
				$cache = $this->redis ->get($redis_key);
			}
			if (!empty($cache)) {//有缓存则直接返回
				return $cache;
			}
			
			$accessToken = $this -> getAccessToken();
			
			$url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=$accessToken";
			$res = json_decode($this -> httpGet($url));
			$ticket = isset($res->ticket)?$res->ticket:'';
			if ($ticket) {
                $this->redis?$this->redis->set($redis_key, $ticket, $expire):'';
			}

			return $ticket;
		}
	}

	private function httpGet($url) {
		$curl = curl_init();
		curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($curl, CURLOPT_TIMEOUT, 500);
		curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
		curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
		curl_setopt($curl, CURLOPT_URL, $url);

		$res = curl_exec($curl);
		curl_close($curl);

		return $res;
	}

    /**
     * 默认授权令牌
     * @var String
     */
    public function getAuthSignStr($arrInput,$arrAuth = array()) {

        $appid = isset($arrAuth['appid'])?$arrAuth['appid']:'';
        $appsecret = isset($arrAuth['appsecret'])?$arrAuth['appsecret']:'';
        $arrInput['appid'] = $appid;

        $arrTrans = array_change_key_case(array_filter($arrInput, function($arrInput){return $arrInput !== '';}), CASE_LOWER);
        $strTrans = '';
        // 按key值升序排序
        if (ksort($arrTrans)) {
            foreach ($arrTrans as $key => $value) {
                if ($key == 'sign') {
                    continue;
                }
                $strTrans .= $key . $value;
            }
            $strSign = md5($strTrans . $appsecret);
        }

        return strtoupper($strSign);
    }

    /**
     * http请求
     */
    public function https_request($url, $data = null) {

        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_TIMEOUT, 5);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
        if (!empty($data)) {
            curl_setopt($curl, CURLOPT_POST, 1);
            curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
        }
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        $result = curl_exec($curl);
        if (curl_errno($curl)) {
            return 'ERROR ' . curl_error($curl);
        }
        curl_close($curl);
        return $result;
    }
}
